package com.blue.common.utils;

import cn.idev.excel.EasyExcel;
import cn.idev.excel.ExcelWriter;
import cn.idev.excel.support.ExcelTypeEnum;
import cn.idev.excel.write.metadata.WriteSheet;
import cn.idev.excel.write.metadata.style.WriteCellStyle;
import cn.idev.excel.write.metadata.style.WriteFont;
import cn.idev.excel.write.style.HorizontalCellStyleStrategy;
import com.blue.common.entity.ExcelBaseRow;
import com.blue.common.entity.ExportMultiSheetParam;
import com.blue.common.entity.ExportParam;
import com.blue.common.exception.CustomException;
import com.blue.common.listener.ExcelDataImportListener;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.poi.ss.SpreadsheetVersion;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.springframework.util.ObjectUtils;
import org.springframework.web.multipart.MultipartFile;

import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

public class ExcelUtils {


    /**
     * 导出文件
     *
     * @param response    http响应
     * @param exportParam 导出参数
     * @param <T>         泛型
     */
    public static <T> void export(HttpServletResponse response, ExportParam<T> exportParam) {
        try {
            // 解除Cell内容长度32767的限制
            initCellMaxTextLength();
            // 响应设置
            response.setHeader("Content-Type", "application/vnd.ms-excel");
            response.setHeader("Content-Disposition", "attachment;filename=" +
                    URLEncoder.encode(exportParam.getFileName(), StandardCharsets.UTF_8) + ExcelTypeEnum.XLSX.getValue());
            response.setCharacterEncoding("UTF-8");
            // 设置导出对象类型和返回类型
            ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream(), exportParam.getClazz())
                    .excelType(ExcelTypeEnum.XLSX)
                    .build();
            // 设置sheet名称和普通默认样式
            WriteSheet writeSheet = EasyExcel.writerSheet(exportParam.getSheetName())
                    .registerWriteHandler(getDefaultStyleStrategy())
                    .build();
            // 填充序号值
            if (exportParam.getClazz().getSuperclass().equals(ExcelBaseRow.class)) {
                AtomicInteger index = new AtomicInteger(0);
                exportParam.getDataList().forEach(data -> ((ExcelBaseRow) data).setIndex(index.incrementAndGet()));
            }
            // 导出数据写入
            excelWriter.write(exportParam.getDataList(), writeSheet);
            // EasyExcel 导出完成自动关闭流，也是可以再手动关一次的（官网这么写的）
            excelWriter.finish();
        } catch (Exception e) {
            throw new CustomException("excel导出失败");
        }
    }

    /**
     * easyExcel 导出多Sheet文件
     *
     * @param response http响应
     * @param param    导出参数
     */
    public static <T> void exportMultiSheet(HttpServletResponse response, ExportMultiSheetParam<T> param) {
        try {
            if (ObjectUtils.isEmpty(param) || ObjectUtils.isEmpty(param.getSheets())) {
                return;
            }
            // 解除Cell内容长度32767的限制
            initCellMaxTextLength();
            // 响应设置
            response.setHeader("Content-Type", "application/vnd.ms-excel");
            response.setHeader("Content-Disposition", "attachment;filename=" +
                    URLEncoder.encode(param.getFileName(), StandardCharsets.UTF_8) + ExcelTypeEnum.XLSX.getValue());
            response.setCharacterEncoding("UTF-8");
            ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream())
                    .excelType(ExcelTypeEnum.XLSX)
                    .build();
            param.getSheets().forEach(sheet -> {
                // 设置sheet名称和普通默认样式
                WriteSheet writeSheet = EasyExcel.writerSheet(sheet.getSheetName())
                        .head(sheet.getClazz())
                        .registerWriteHandler(getDefaultStyleStrategy())
                        .build();
                // 填充序号值
                if (sheet.getClazz().getSuperclass().equals(ExcelBaseRow.class)) {
                    AtomicInteger index = new AtomicInteger(0);
                    sheet.getDataList().forEach(data -> ((ExcelBaseRow) data).setIndex(index.incrementAndGet()));
                }
                // 导出数据写入
                excelWriter.write(sheet.getDataList(), writeSheet);
            });
            // EasyExcel 导出完成自动关闭流，也是可以再手动关一次的（官网这么写的）
            excelWriter.finish();
        } catch (Exception e) {
            throw new CustomException("excel导出失败");
        }
    }

    /**
     * easyExcel 导入解析
     *
     * @param file  导入文件
     * @param clazz 导入对象类
     */
    public static <T> List<T> parse(MultipartFile file, Class<T> clazz) {
        try {
            List<T> dataList = new ArrayList<>();
            ExcelDataImportListener<T> excelDataImportListener = new ExcelDataImportListener<T>(clazz, dataList);
            // 读取excel数据到result集合中
            EasyExcel.read(file.getInputStream(), clazz, excelDataImportListener)
                    .sheet()
                    // 去除文件中的一行标题行
                    .headRowNumber(1)
                    .doRead();

            return dataList;
        } catch (Exception e) {
            throw new CustomException("Excel文件读取失败");
        }
    }

    /**
     * 初始化 cell 内容长度
     * cell 原本内容长度限制 32767  现修改为Integer.MAX_VALUE
     */
    public static void initCellMaxTextLength() {
        SpreadsheetVersion excel2007 = SpreadsheetVersion.EXCEL2007;
        if (Integer.MAX_VALUE != excel2007.getMaxTextLength()) {
            Field field;
            try {
                field = excel2007.getClass().getDeclaredField("_maxTextLength");
                field.setAccessible(true);
                field.set(excel2007, Integer.MAX_VALUE);
            } catch (Exception e) {
                throw new CustomException(e.getMessage());
            }
        }
    }

    /**
     * easyExcel样式模板
     * 格表头 11号、加粗、宋体
     * 内容 10号
     *
     * @return 样式模板
     */
    private static HorizontalCellStyleStrategy getDefaultStyleStrategy() {
        // 表头样式居中对齐、字体宋体11号不加粗（默认加粗）、自动换行（已默认）
        WriteFont writeFont = new WriteFont();
        writeFont.setBold(false);
        writeFont.setFontName("宋体");
        writeFont.setFontHeightInPoints((short) 10);
        WriteCellStyle headWriteCellStyle = new WriteCellStyle();
        headWriteCellStyle.setWriteFont(writeFont);
        headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
        // 内容样式垂直、水平居中、字体宋体10号不加粗（默认不加粗）、自动换行
        WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
        contentWriteCellStyle.setBorderTop(BorderStyle.THIN);
        contentWriteCellStyle.setBorderBottom(BorderStyle.THIN);
        contentWriteCellStyle.setBorderLeft(BorderStyle.THIN);
        contentWriteCellStyle.setBorderRight(BorderStyle.THIN);
        contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
        contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        contentWriteCellStyle.setWrapped(true);
        contentWriteCellStyle.setWriteFont(writeFont);
        return new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
    }
}
